﻿using System;
using System.Collections.Generic;
using System.Text;
using IBatisNet.DataMapper;
using IBatisNet.DataMapper.Configuration;
using Common.Utils;
using System.IO;
using System.Xml;
using System.Collections.Specialized;
using Common.Configuration;
using IBatisNet.Common.Exceptions;
using System.Collections;
using IBatisNet.Common.Pagination;
using System.Data;
using IBatisNet.DataMapper.Scope;
using IBatisNet.DataMapper.MappedStatements;

namespace Common
{
    public abstract class IBatisHelper
    {
        ISqlMapper _sqlMap;
        public IBatisHelper(string providerName, string connectionString, Type type, string embededSqlMapFile)
        {
            NameValueCollection properties = new NameValueCollection();
            properties.Add("providerName", providerName);
            properties.Add("connectionString", connectionString);

            DomSqlMapBuilder builder = new DomSqlMapBuilder();
            builder.Properties = properties;
            Stream stream = ResourceUtil.GetResourceStream(type, embededSqlMapFile);
            ISqlMapper sqlMap = builder.Configure(stream);
            _sqlMap = sqlMap;
        }

        protected ISqlMapper GetSqlMapper()
        {
            return _sqlMap;
        }

        public object Insert(string statementName,object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.Insert(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for insert.  Cause: " + e.Message, e);
            }
        }

        public int Update(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.Update(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for update.  Cause: " + e.Message, e);
            }
        }

        public int Delete(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.Delete(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for delete.  Cause: " + e.Message, e);
            }
        }

        public T Get<T>(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.QueryForObject<T>(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for query object.  Cause: " + e.Message, e);
            }
        }        

        public IList GetList(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.QueryForList(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for query list.  Cause: " + e.Message, e);
            }
        }

        public List<T> GetList<T>(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return (List<T>)sqlMap.QueryForList<T>(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for query list.  Cause: " + e.Message, e);
            }
        }

        public IList GetList(string statementName, object parameterObject, int start, int limit)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.QueryForList(statementName, parameterObject, start, limit);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for query list.  Cause: " + e.Message, e);
            }
        }
        
        public ISqlMapSession BeginTransaction(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                return sqlMap.BeginTransaction();
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for begin trans.  Cause: " + e.Message, e);
            }
        }

        public void CommitTransaction(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                sqlMap.CommitTransaction();
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for commit trans.  Cause: " + e.Message, e);
            }
        }

        public void RollBackTransaction(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetSqlMapper();

            try
            {
                sqlMap.RollBackTransaction();
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for rollback trans.  Cause: " + e.Message, e);
            }
        }


        public DataSet GetDataSet(string statementName, object paramObject)
        {
            try
            {
                DataSet ds = new DataSet();
                ISqlMapper mapper = GetSqlMapper();
                IMappedStatement statement = mapper.GetMappedStatement(statementName);
                if (!mapper.IsSessionStarted)
                {
                    mapper.OpenConnection();
                }
                RequestScope scope = statement.Statement.Sql.GetRequestScope(statement, paramObject, mapper.LocalSession);
                statement.PreparedCommand.Create(scope, mapper.LocalSession, statement.Statement, paramObject);

                IDbCommand dc = mapper.LocalSession.CreateCommand(scope.IDbCommand.CommandType);
                dc.CommandText = scope.IDbCommand.CommandText;
                foreach (IDbDataParameter para in scope.IDbCommand.Parameters)
                {
                    IDbDataParameter p = mapper.LocalSession.CreateDataParameter();
                    p.DbType = para.DbType;
                    p.Direction = para.Direction;
                    p.ParameterName = para.ParameterName;
                    p.Precision = para.Precision;
                    p.Scale = para.Scale;
                    p.Size = para.Size;
                    p.SourceColumn = para.SourceColumn;
                    p.SourceVersion = para.SourceVersion;
                    p.Value = para.Value;
                    dc.Parameters.Add(p);
                }
                IDbDataAdapter dda = mapper.LocalSession.CreateDataAdapter(dc);
                dda.Fill(ds);
                foreach (IDbDataParameter para in scope.IDbCommand.Parameters)
                {
                    if (para.Direction == ParameterDirection.Output)
                    {
                        if (paramObject is Hashtable)
                        {
                            Hashtable ht = (Hashtable)paramObject;
                            ht[para.ParameterName.Replace("@", "")] = ((System.Data.Common.DbParameter)(dc.Parameters[para.ParameterName])).Value;
                        }
                    }
                }
                return ds;
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for DataSet.  Cause: " + e.Message, e);
            }
        }


        public string GetSqlString(string statementName, object paramObject)
        {
            ISqlMapper mapper = GetSqlMapper();
            IMappedStatement statement = mapper.GetMappedStatement(statementName);
            if (!mapper.IsSessionStarted)
            {
                mapper.OpenConnection();
            }
            RequestScope scope = statement.Statement.Sql.GetRequestScope(statement, paramObject, mapper.LocalSession);

            return scope.PreparedStatement.PreparedSql;
        }

    }
}
